package cn.jofei.netty.server;

import cn.jofei.common.ano.Component;
import cn.jofei.common.ano.Value;
import cn.jofei.common.config.AppProperties;
import cn.jofei.netty.hadler.HttpServerHandler;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpRequestDecoder;
import io.netty.handler.codec.http.HttpServerCodec;
import lombok.extern.slf4j.Slf4j;

import java.util.Locale;

/**
 * HTTP消息处理器
 *
 * @author Jofei Bao
 * @version ngbao v2.0
 * @date 2022年10月18日 11:29
 */
@Slf4j
@Component
public class SocketHttpServer extends SocketServer {

    @Value(name = "${server.listen.http.port}")
    private Integer httpPort = 80;

    @Value(name = "${server.listen.http.max-content-length}")
    private Integer maxContentLength = 5 * 1024 * 1024;

    static Integer HEADER_SIZE;

    static {
        String head = AppProperties.get("server.listen.header-size").toLowerCase(Locale.ROOT);
        if (head.endsWith("k")) {
            HEADER_SIZE = Integer.parseInt(head.replaceAll("k", "")) * 1024;
        } else if (head.endsWith("m")) {
            HEADER_SIZE = Integer.parseInt(head.replaceAll("m", "")) * 1024 * 1024;
            HEADER_SIZE = HEADER_SIZE > 2 * 1024 * 1024 ? 2 * 1024 * 1024 : HEADER_SIZE;
        } else
            HEADER_SIZE = 8 * 1024;
    }

    @Override
    public void start() {
        ServerBootstrap bootstrap = new ServerBootstrap();
        bootstrap.group(BOSS_GROUP, WORK_GROUP)
                .channel(NioServerSocketChannel.class)
                // 给 ServerSocketChannel 的配置 连接队列数配置 accept 处理的队列
                .option(ChannelOption.SO_BACKLOG, 256)
                // 给 SocketChannel 的配置
                .childOption(ChannelOption.SO_KEEPALIVE, true)
                .childHandler(new ChannelInitializer<NioSocketChannel>() {
                    @Override
                    protected void initChannel(NioSocketChannel sc) throws Exception {
                        sc.pipeline()
                                .addLast(LOGGING_HANDLER)
                                // http 请求解析
                                .addLast("http-decoder", new HttpServerCodec(4096, HEADER_SIZE, 8192))
                                // http 请求 聚合
                                .addLast("Aggregator", new HttpObjectAggregator(maxContentLength))
                                // http 请求处理器
                                .addLast(new HttpServerHandler())
                        ;
                    }
                });
        bootstrap.bind(httpPort).addListener(e -> {
            if (e.isSuccess()) {
                log.info("创建 HTTP 监听端口：{} 成功", httpPort);
            } else {
                log.error("创建 HTTP 监听端口异常", e.cause());
            }
        });
    }
}
